package com.ziytek.web.citizen.quartz.execute;

import cn.idev.excel.util.StringUtils;
import com.google.gson.Gson;
import com.ziytek.web.citizen.caffeine.CachePutOrGet;
import com.ziytek.web.citizen.config.caffeine.CaffeineUtil;
import com.ziytek.web.citizen.constant.NumConstant;
import com.ziytek.web.citizen.constant.ServerConstant;
import com.ziytek.web.citizen.constant.TableConstant;
import com.ziytek.web.citizen.mapper.TableMapper;
import com.ziytek.web.citizen.model.bean.JobTimes;
import com.ziytek.web.citizen.model.vo.RealTimeDo;
import com.ziytek.web.citizen.model.vo.RealTimeVo;
import com.ziytek.web.citizen.service.BatchNoService;
import com.ziytek.web.citizen.service.BatteryStatsService;
import com.ziytek.web.citizen.service.CompressionService;
import com.ziytek.web.citizen.service.OperationVoCacheService;
import com.ziytek.web.citizen.util.KeyUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;


/**
 * @author fengh
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class StepIssuedEventListenerQuartzJob implements Job {
    private final Gson gson;
    private final TableMapper tableMapper;
    private final CachePutOrGet cachePutOrGet;
    private final BatchNoService batchNoService;
    private final CompressionService compressionService;
    private final BatteryStatsService batteryStatsService;
    private final OperationVoCacheService operationVoCacheService;

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        var oldTimes = NumConstant.INT_ZERO;
        var repeatCount = NumConstant.INT_ZERO;
        if (context.getTrigger() instanceof SimpleTrigger trigger) {
            oldTimes = trigger.getTimesTriggered();
            repeatCount = trigger.getRepeatCount();
        }

        JobDataMap dataMap = context.getMergedJobDataMap();
        JobTimes jobTimes = (JobTimes) dataMap.get(ServerConstant.JOB_TIMES);
        if (null == jobTimes) {
            return;
        }

        if (null != jobTimes.getOrderOneFirstError() && jobTimes.getOrderOneFirstError()) {
            jobTimes.setTimes(oldTimes);
            jobTimes.setTimeCount(repeatCount + NumConstant.INT_ONE);
            var key = KeyUtil.jobTimesKey(jobTimes);
            CaffeineUtil.set(key, jobTimes);
            log.info("一开始就是异常数据定时任务执行,repeatCount:{},times:{}->{}", repeatCount, oldTimes, gson.toJson(jobTimes));
            return;
        }

        // 定时任务执行次数小于等于0，则不执行
        //if (repeatCount <= NumConstant.INT_ZER || times == NumConstant.INT_ONE) {
        if (repeatCount <= NumConstant.INT_ZERO || oldTimes <= NumConstant.INT_ONE) {
            log.info("定时任务执行次数小于等于0,不执行,repeatCount:{},times:{}", repeatCount, oldTimes);
            return;
        }

        //log.info("定时任务执行次数,repeatCount:{},times:{}-{}", repeatCount, oldTimes, gson.toJson(jobTimes));

        jobTimes.setTimes(oldTimes);
        jobTimes.setTimeCount(repeatCount + NumConstant.INT_ONE);
        var boardNo = jobTimes.getBoardNo();
        var cabinetNo = jobTimes.getCabinetNo();
        var channelNo = jobTimes.getChannelNo();
        var commandType = jobTimes.getCommandType();
        var key = KeyUtil.jobTimesKey(jobTimes);
        CaffeineUtil.set(key, jobTimes);

        var interruptKey = cabinetNo + CaffeineUtil.CACHE_KEY_SYMBOL + boardNo + CaffeineUtil.CACHE_KEY_SYMBOL + channelNo;

        var interruptStats = cachePutOrGet.getInterruptStatsCache(interruptKey);
//        int interruptCount = 0;
//        //boolean interrupt = false;
//        if (interruptStats != null) {
//            //interrupt = true;
//            interruptCount = interruptStats.getInterruptBeforeTimes();
//            //log.info("中断0统计：{}-time:{}-count:{}-ts:{}", interruptKey, interruptTime, interruptCount, interruptStats.ts);
//        }

        int interruptCount = null != interruptStats ? interruptStats.getInterruptBeforeTimes() : NumConstant.INT_ZERO;
        //if (interrupt && oldTimes <= NumConstant.INT_FOUR) {
//        if (interrupt && oldTimes == NumConstant.INT_TWO) {
        // if (interrupt) {
        // log.info("中断统计前2次不进行统计key:{},interruptCount:{},oldTimes:{}", interruptKey, interruptCount, oldTimes);
        //return;
        //}

        var times = oldTimes + interruptCount;
        // 中断过的需要减3
        // if (interrupt) {
        //times -= NumConstant.INT_THREE;
        //}

        // 单个通道指令下发的定时任务
        var rd = batteryStatsService.getSignalRealTimeVo(Integer.parseInt(String.valueOf(cabinetNo)), boardNo, channelNo);
        if (null == rd || null == rd.getData()) {
            log.info("定时任务没有数据key[{}],times[{}]", key, times);
            return;
        }

        addSingleRealTime(rd, times, commandType);
    }


    public void end(JobTimes jobTimes, int times, int repeatCount) {
        if (null == jobTimes) {
            return;
        }

        jobTimes.setTimes(times);
        jobTimes.setTimeCount(repeatCount + NumConstant.INT_ONE);
        var boardNo = jobTimes.getBoardNo();
        var cabinetNo = jobTimes.getCabinetNo();
        var channelNo = jobTimes.getChannelNo();
        var commandType = jobTimes.getCommandType();
        var key = KeyUtil.jobTimesKey(jobTimes);
        CaffeineUtil.set(key, jobTimes);

        // 单个通道指令下发的定时任务
        var rd = batteryStatsService.getSignalRealTimeVo(Integer.parseInt(String.valueOf(cabinetNo)), boardNo, channelNo);
        if (null == rd || null == rd.getData()) {
            log.info("定时任务没有数据key:{},times:{}", key, times);
            return;
        }

        addSingleRealTime(rd, times, commandType);
    }

    private void addSingleRealTime(RealTimeDo rd, int times, String commandType) {
        if (null == rd) {
            return;
        }

        if (times <= NumConstant.INT_TWO) {
            byte[] data;
            try {
                data = compressionService.decompress(rd.getData());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            var rvo = gson.fromJson(new String(data, StandardCharsets.UTF_8), RealTimeVo.class);
            if (null == rvo) {
                return;
            }

            if (!rvo.getCty().equalsIgnoreCase(commandType)) {
                rvo.setCty(commandType);
                byte[] bytes = gson.toJson(rvo).getBytes(StandardCharsets.UTF_8);
                try {
                    byte[] dataCompress = compressionService.compress(bytes);
                    rd.setData(dataCompress);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        rd.setTime((times - NumConstant.INT_TWO) * NumConstant.LONG_TEN);
        if (StringUtils.isBlank(rd.getBatchNo())) {
            var opKey = KeyUtil.commandOperateKey(rd.getCn(), rd.getBn(), rd.getCnn());
            var vo = operationVoCacheService.getOperationVo(opKey);
            rd.setBatchNo("0000");
            if (vo != null && StringUtils.isNotBlank(vo.getBatchNo())) {
                // 获取批次号
                rd.setBatchNo(vo.getBatchNo());
            } else {
                var bn = batchNoService.queryOne(rd.getCn());
                rd.setBatchNo(null != bn && StringUtils.isNotBlank(bn.getBatchNo()) ? bn.getBatchNo() : "0000");
            }
        }
        try {
            tableMapper.addSingleRealTime(TableConstant.TABLE_REAL_TIME + rd.getBn(), rd);
        } catch (Exception e) {
            log.error("error:{}", gson.toJson(rd));
        }
    }
}
